package com.hy.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hy.constans.HttpStatus;
import com.hy.constans.PropertiesConfig;
import com.hy.domain.User;
import com.hy.domain.dto.LoginFormDTO;
import com.hy.domain.dto.R;
import com.hy.domain.dto.RegisterFormDTO;
import com.hy.domain.dto.UserDTO;
import com.hy.exception.BusinessException;
import com.hy.service.UserService;
import com.hy.mapper.UserMapper;
import com.hy.util.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.hy.util.RedisConstants.*;

/**
* @author hou
* @description 针对表【user】的数据库操作Service实现
* @createDate 2023-04-14 23:13:06
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisIdWorker redisIdWorker;

    @Autowired
    private PropertiesConfig config;

    @Autowired
    private UserMapper userMapper;

//    @Autowired
//    private UserFriendService userFriendService;

    /**
     * 登录
     * @param loginForm 登录表单的数据
     * @return
     */
    @Override
    public R login(LoginFormDTO loginForm) {
        String username = loginForm.getUsername();

        if (username == null || "".equals(username) ||
            !(RegexUtils.isEmailInvalid(username) || RegexUtils.isPhoneInvalid(username))) {
            return R.fail("请输入正确的用户名！");
        }

        User user = query()
                .eq("user_name", username).or()
                .eq("email", username).or()
                .eq("phone", username).one();

        if (user == null || !PasswordEncoder.matches(user.getPassword(), loginForm.getPassword())) {
            return R.fail("登陆失败！用户名或密码错误！");
        }

        final String code = loginForm.getCode();
        final String uuid = loginForm.getUuid();
        final String realCode = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY + uuid);
        if (!StrUtil.equals(code, realCode)) {
            return R.fail("验证码错误！");
        }

        // 登录成功，生成token
        String token = TokenUtils.getToken(user.getUserId().toString(), user.getPassword());
        // TODO 将用户信息保存到redis
        // 数据脱敏
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        UserHolder.saveUser(userDTO);
        saveUserInfoToRedis(userDTO, token);


        // 更新redis中好友关系

//        final List<Long> ids = .listIdsByUserId(user.getUserId());
        return R.ok(token).message("欢迎登陆，" + userDTO.getNickName() + "!");
    }

    private void saveUserInfoToRedis(UserDTO userDTO, String token) {
        String tokenKey = LOGIN_USER_KEY + token;
        // 转换成map
        Map<String, Object> map = BeanUtil.beanToMap(userDTO, new HashMap<>(), CopyOptions
                .create()
                .setIgnoreNullValue(true)
                .setFieldValueEditor((key, value) -> value == null ? "" : value.toString()));
        System.out.println("map = " + map);
        stringRedisTemplate.opsForHash().putAll(tokenKey, map);
        // 设置TTL
        stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);
    }

    @Override
    public R register(RegisterFormDTO form) {
        System.out.println("form = " + form);
        String email = form.getEmail();
        String phone = form.getPhone();
        String nickName = form.getNickName();
        String password = form.getPassword();
        String code = form.getCode();
        String uuid = form.getUuid();
        // 验证

        if (uuid == null || uuid.equals("")) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "错误的请求");
        }

        if (nickName == null || "".equals(nickName)) {
            return R.fail("昵称不能为空！");
        }

        if (StrUtil.isNotEmpty(email) && RegexUtils.isEmailInvalid(email)) {
            return R.fail("邮箱地址输入错误！");
        }

        if (StrUtil.isNotEmpty(phone) && !RegexUtils.isPhoneInvalid(email)) {
            return R.fail("手机号输入错误！");
        }

        if (password == null || "".equals(password)) {
            return R.fail("密码不能为空！");
        }
        System.out.println("RegexUtils.isPasswordInvalid(password) = " + RegexUtils.isPasswordInvalid(password));
        if (!RegexUtils.isPasswordInvalid(password)) {
            return R.fail("密码不满足条件！");
        }

        String key = RedisConstants.LOGIN_CODE_KEY + uuid;
        String realCode = stringRedisTemplate.opsForValue().get(key);

        if (!StrUtil.equals(realCode, code)) {
            return R.fail("验证码错误");
        }
        // 判断手机号是否已经注册
//        Integer count = query().eq("phone", phone).or().eq("email", email).count();
//        if (count > 0) {
//            return R.fail("手机号或邮箱已经被注册");
//        }

        Integer count = userMapper.selectCountByEmailOrPhone(email, phone);
        System.out.println("count = " + count);
        if (count != null) {
            return R.fail("手机号或邮箱已经被注册");
        }

        // 生成用户名
        String userName = randomUserName();

        User user = new User();
        BeanUtils.copyProperties(form, user);
        user.setPassword(PasswordEncoder.encode(password));
        user.setAvatar(config.getDefaultAvatar()); // 设置默认头像
        user.setUserName(userName); // 随机生成一个用户名
        LocalDateTime now = LocalDateTime.now();
        user.setCreateTime(now);
        user.setUpdateTime(now);
        save(user);
        return R.ok(userName).message("注册成功！");
    }

    @Override
    public String randomUserName() {
        StringBuilder sb = new StringBuilder();
        LocalDateTime now = LocalDateTime.now();
        long reg = redisIdWorker.nextUserNameId("reg");
        return now.format(DateTimeFormatter.ofPattern("yyMMss")) + StrUtil.fillBefore(reg + "", '0', 4);
    }

    @Override
    public R logout() {
        WebsocketUtil.removeSession(UserHolder.getUser().getUserId());
        UserHolder.removeUser();
        return R.ok();
    }

    @Override
    public List<User> search(String keyword) {
        final List<User> list = query()
                .or().eq("user_name", keyword)
                .or().like("nick_name", keyword)
                .or().like("phone", keyword)
                .list();
        return list;
    }

    @Override
    public void updatePwd(String oldPwd, String newPwd) throws Exception {
        final Long userId = UserHolder.getUser().getUserId();
        // 根据用户ID查询数据库
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserId,userId);
        User user = this.getOne(queryWrapper);

        // 没有查询到用户
        if(user == null){
            throw new BusinessException(HttpStatus.BAD_REQUEST, "请登录");
        }
        // 原密码错误
        System.out.println("user = " + user);
        System.out.println("oldPwd = " + oldPwd);
        System.out.println("newPwd = " + newPwd);

        if(!PasswordEncoder.matches(user.getPassword(), oldPwd)){
            throw new BusinessException(HttpStatus.BAD_REQUEST, "原密码错误");
        }

        User user2 = new User();
        user2.setUserId(userId);
        user2.setPassword(PasswordEncoder.encode(newPwd));
        this.updateById(user2);
    }

    @Override
    public void updateUserInfo(UserDTO user, HttpServletRequest request) {
        final Long userId = UserHolder.getUser().getUserId();
        System.out.println("user = " + user);
        user.setUserId(userId);
        final User saveUser = BeanUtil.copyProperties(user, User.class);
        updateById(saveUser);
        final UserDTO dto = UserHolder.getUser();
        BeanUtil.copyProperties(user, dto);
        String token = request.getHeader("authorization");
        saveUserInfoToRedis(user, token);
        System.out.println("getUser() = " + UserHolder.getUser());
    }
}




